﻿using Cinemachine;
using Cysharp.Threading.Tasks;
using Data;
using Factory;
using Hero;
using Logic;
using Services.Loot;
using Services.Progress;
using Services.Window;
using System;
using UI.Support;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Infrastructure.States
{
    public class LoadLevelState : IPayloadedState<string>
    {
        private readonly GameStateMachine _stateMachine;
        private readonly SceneLoader _sceneLoader;
        private readonly LoadingCurtain _loadingCurtain;
        private readonly IGameFactory _gameFactory;
        private readonly IProgressService _progressService;
        private readonly ILootService _lootService;
        private readonly IWindowService _windowService;
        private GameSceneData _data;

        public LoadLevelState(
            GameStateMachine stateMachine,
            SceneLoader sceneLoader,
            LoadingCurtain loadingCurtain,
            IGameFactory gameFactory,
            IProgressService progressService, 
            ILootService lootService, 
            IWindowService windowService)
        {
            _stateMachine = stateMachine;
            _sceneLoader = sceneLoader;
            _loadingCurtain = loadingCurtain;
            _gameFactory = gameFactory;
            _progressService = progressService;
            _lootService = lootService;
            _windowService = windowService;
        }

        public void Enter(string sceneName)
        {
            _data = _progressService.Progress.GameSceneData;
            _loadingCurtain.Show();
            _sceneLoader.Load(sceneName, OnLoaded).Forget();
        }

        public void Exit()
        {

        }

        private async void OnLoaded()
        {
            var pause = Object.FindAnyObjectByType<Pause>();
            pause.enabled  =  false;
            _windowService.Open(WindowId.Root);
            var camera = InitCamera();
            _loadingCurtain.Hide().Forget();
            await _gameFactory.CreateGameField();
            var (health, reload, score, shoot) = InitHero();
            _lootService.InitLootService(health, reload, score, shoot);
            InitHud(health, reload, score, shoot);
            FollowCamera(camera, health.transform);
            await UniTask.Delay(TimeSpan.FromSeconds(_data.CreateAnimationTime));
            pause.enabled  =  true;
            _stateMachine.Enter<GameLoopState>();
        }

        private void FollowCamera(CinemachineVirtualCamera camera, Transform hero)
        {
            camera.Follow = hero;
            camera.LookAt = hero;
        }

        private CinemachineVirtualCamera InitCamera()
        {
            var camera = GameObject.FindWithTag(Constants.VirtualCameraTag);
            camera.TryGetComponent<CinemachineVirtualCamera>(out var virtualCamera);
            _data.VirtualCamera = virtualCamera;
            virtualCamera.m_Lens.OrthographicSize = _data.CameraSize;
            return virtualCamera;
        }

        private (HeroHealth Health, HeroReload Reload, HeroScore Score, HeroShoot Shoot) InitHero() =>
            _gameFactory.CreateHero(_data.HeroSpawnPoint);

        private void InitHud(HeroHealth health, HeroReload reload, HeroScore score, HeroShoot shoot) =>
            _gameFactory.CreateHud(health, reload, score, shoot);
    }
}